#include <stdbool.h>

/**
 * @brief 子密钥
 */
typedef struct SUBKEY {
    bool key[16][48];
} *SUBKEY_P;

/**  
 * @brief 标准DES加/解密  
 * 
 * @param out 输出的8字节数据  
 * @param in 输入的8字节数据  
 * @param pskey 指向DES子密钥的指针，用于加密或解密过程  
 * @param type 如果为true，则执行加密操作，如果为false，则执行解密操作  
 * 
 * @note `out`和`in`可以相同
 * 
 */  
static void DES(char out[8], char in[8], const SUBKEY_P pskey, bool type);

/**  
 * @brief 设置子密钥  
 * 
 * @param pskey 指向子密钥数组的指针，用于存储生成的子密钥  
 * @param key 包含8字节的数组，用作生成子密钥的原始密钥  
 * 
 * @note
 * DES加密算法使用了一个64位的密钥，  
 * 但在实际加密/解密过程中，需要16个48位的子密钥。  
 * 本函数根据输入的8字节密钥生成这些子密钥，并将它们存储在提供的子密钥数组中。  
 * 
 */  
static void Set_SubKey(SUBKEY_P pskey, const char key[8]);

/**  
 * @brief F函数  
 *  
 * @param out 32位的输出数组，用于存储F函数的结果  
 * @param in 32位的输入数组  
 * @param ki 48位的子密钥，与扩展置换后的输入进行异或操作  
 *  
 * @note  
 * F函数是DES加密算法中的一个关键组件，它完成扩展置换（E-box）、S-盒代替（Substitution-boxes）和P盒置换（P-box permutation）。  
 * F函数接收两个输入：一个32位的输入数组 `in` 和一个48位的子密钥 `ki`。  
 * 它首先通过扩展置换（E-box）将32位的输入扩展到48位，然后与48位的子密钥进行异或操作。  
 * 接着，48位的结果被分为8个6位的块，每个块通过S-盒代替（Substitution-boxes）被映射为一个4位的输出。  
 * 最后，8个4位的输出通过P盒置换（P-box permutation）被重新排列成一个32位的输出`out`。
 * 
 */  
static void F_FUNCTION(bool out[32], const bool in[32], const bool ki[48]);

/**  
 * @brief S-盒代替函数  
 *  
 * @param out 32位的输出数组，存储S-盒代替后的结果
 * @param in 48位的输入数组，用于S-盒代替操作  
 * 
 * @note
 * S_BOXF 函数接收一个48位的输入数组 `in`，并将其分成8个6位的块。  
 * 对于每个6位的块，使用DES加密算法的S-盒进行代替操作，产生一个4位的输出。  
 * 最终，这8个4位的输出被组合成一个32位的输出数组 `out`。  
 * 
 */  
static void S_BOXF(bool out[32], const bool in[48]);

/**  
 * @brief 变换
 *  
 * @param out 指向输出布尔值数组的指针，用于存储变换后的结果  
 * @param in 指向输入布尔值数组的指针，包含待变换的数据  
 * @param table 指向变换表的指针，该表定义了如何进行变换  
 * @param len `table`的长度
 * 
 * @note `in`和`out`不应该是同一个数组，甚至不应该有重叠。
 * 
 * @example  
 * bool in[] = {0,1,1,1, 0,1,0,1};  
 * const char table[] = {7, 6, 5, 4};
 * bool out[8];
 * TRANSFORM(out, in, table, 4);
 * // out 的内容现在应该是 {1,0,1,0}
 * 
 */
static void TRANSFORM(bool *out, const bool *in, const char *table, int len);

/**  
 * @brief 异或函数  
 * 
 * @param inA 指向第一个布尔值数组的指针，既是输入也是输出（存储异或结果）  
 * @param inB 指向第二个布尔值数组的指针
 * @param len 输入数组的长度  
 * 
 */  
static void XOR(bool *inA, const bool *inB, int len);

/**  
 * @brief 循环左移函数  
 *  
 * @param in 指向布尔值数组的指针
 * @param len 数组的长度  
 * @param loop 循环左移的位数  
 *  
 * @note 循环左移的位数`loop`不应该超过数组的长度`len`
 * 
 * @example
 * bool in[4] = {1, 0, 0, 1};
 * CYCLELEFT(in, 4, 1);
 * // in 的内容现在应该是 {0, 0, 1, 1}
 * 
 */  
static void CYCLELEFT(bool *in, int len, int loop);

/**    
 * @brief 字节数组转换成比特数组
 *  
 * @param out 指向输出比特数组的指针，用于存储转换后的比特数据  
 * @param in 指向输入字节数组的指针，包含待转换的字节数据  
 * @param bits 需要转换的位数，应为8的倍数  
 * 
 * @note 每个字节（8位）被分解为8个独立的位，  
 * 同一字节的8个位按照从高位到低位的顺序存放（大端编址，高位排在左边）。  
 *  
 * @example  
 * char byteArray[] = {0x01, 0xFE}; // 示例字节数组  
 * bool bitArray[16];
 * int bits = 16; // 需要转换的位数  
 * // 调用函数进行转换
 * ByteToBit(bitArray, byteArray, bits);
 * // bitArray 的内容现在应该是 {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}
 * 
 */    
static void ByteToBit(bool *out, const char *in, int bits);

/**  
 * @brief 比特数组转换成字节数组
 *  
 * @param out 指向输出字节数组的指针，用于存储转换后的字节数据  
 * @param in 指向输入比特数组的指针，包含待转换的比特数据  
 * @param bits 需要转换的位数，应为8的倍数
 * 
 * @note 每8位连续的位被合并成一个字节，
 * 按照从高位到低位的顺序填充到该字节中（大端编址，高位排在左边）。  
 *  
 * @example  
 * bool bitArray[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}; // 示例比特数组  
 * char byteArray[2];
 * int bits = 16; // 需要转换的位数
 * // 调用函数进行转换  
 * BitToByte(byteArray, bitArray, bits);  
 * // byteArray 的内容现在应该是 {0x01, 0xFE}
 * 
 */  
static void BitToByte(char *out, const bool *in, int bits);
